package com.relytosoft.mizar.analyze.handle.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.relytosoft.dubhe.common.redis.utils.RedisUtil;
import com.relytosoft.mizar.analyze.base.constant.SymbolConstants;
import com.relytosoft.mizar.analyze.base.entity.algo.*;
import com.relytosoft.mizar.analyze.base.entity.pojo.dto.AyDispositionPlanDto;
import com.relytosoft.mizar.analyze.base.entity.pojo.dto.controlCondition.TextNonVehicleConditionDto;
import com.relytosoft.mizar.analyze.base.entity.pojo.dto.controlCondition.TextPeopleConditionDto;
import com.relytosoft.mizar.analyze.base.entity.pojo.dto.controlCondition.TextVehicleConditionDto;
import com.relytosoft.mizar.analyze.base.entity.pojo.dto.controlPlan.TimeSpanDto;
import com.relytosoft.mizar.analyze.base.entity.pojo.request.btdl.common.BtdlFaceControlReq;
import com.relytosoft.mizar.analyze.base.enums.PlanTypeEnum;
import com.relytosoft.mizar.analyze.handle.service.ControlPlanService;
import com.relytosoft.mizar.analyze.handle.service.ControlTypeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import static com.relytosoft.mizar.analyze.base.constant.AyCacheConstants.*;
import static com.relytosoft.mizar.analyze.base.constant.ControlConstants.*;
import static com.relytosoft.mizar.analyze.handle.constant.ErrorConstants.JSON_PARSE_ERROR;

/**
 * @author wss
 * @version 1.0
 * @date 2022/5/23 17:10
 */
@Service
public class ControlPlanServiceImpl implements ControlPlanService {

    protected Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    ControlTypeService controlTypeService;

    @Override
    public Boolean controlFaceAlarm(BtdlFaceControlReq btdlFaceControlReq) {
        String executeControlID = btdlFaceControlReq.getExecuteControlId();
        AyControlFace gaFace = btdlFaceControlReq.getgAFace();
        long markTime = gaFace.getMarkTime();
        Object controlDto = RedisUtil.get(CONTROL_FACE_CONDITION + executeControlID);
        if (Objects.isNull(controlDto)) {
            return false;
        }
        AyDispositionPlanDto ayDispositionPlanDto = JSON.parseObject(controlDto.toString(), AyDispositionPlanDto.class);
        if (!controlFrontVerify(ayDispositionPlanDto, markTime)) {
            return false;
        }
        return controlPlanVerify(ayDispositionPlanDto);
    }

    @Override
    public Boolean controlStructureAlarm(AYVideoSlice ayVideoSlice) {
        Object controlJson = RedisUtil.get(CONTROL_STRUCTURE_CONDITION + ayVideoSlice.getDeviceID());
        if (Objects.isNull(controlJson)) {
            return false;
        }
        List<AyDispositionPlanDto> ayDispositionPlanDtoS = JSON.parseArray(controlJson.toString(), AyDispositionPlanDto.class);
        Iterator<AyDispositionPlanDto> planDtoIterator = ayDispositionPlanDtoS.iterator();
        while (planDtoIterator.hasNext()) {
            AyDispositionPlanDto dispositionPlanDto = planDtoIterator.next();
            if (singleStructureControlVerify(dispositionPlanDto, ayVideoSlice)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 单个布控条件验证
     *
     * @param ayDispositionPlanDto
     * @param ayVideoSlice
     * @return
     */
    public Boolean singleStructureControlVerify(AyDispositionPlanDto ayDispositionPlanDto, AYVideoSlice ayVideoSlice) {
        //前置验证
        if (!controlFrontVerify(ayDispositionPlanDto, System.currentTimeMillis())) {
            return false;
        }
        //布控计划验证
        if (!controlPlanVerify(ayDispositionPlanDto)) {
            return false;
        }
        //结构化条件验证
        return structureConditionVerify(ayVideoSlice, ayDispositionPlanDto);
    }

    /**
     * 结构化布控条件验证
     *
     * @param ayVideoSlice
     * @param ayDispositionPlanDto
     * @return
     */
    public Boolean structureConditionVerify(AYVideoSlice ayVideoSlice, AyDispositionPlanDto ayDispositionPlanDto) {
        List<AYPerson> personList = ayVideoSlice.getPersonList().getPersonObject();
        List<AYVehicle> vehicleList = ayVideoSlice.getMotorVehicleList().getMotorVehicleObject();
        List<AYNonVehicle> nonVehicleList = ayVideoSlice.getNonMotorVehicleList().getNonMotorVehicleObject();
        //遮挡车牌验证
        if (coverVehicleVerify(vehicleList)) {
            return true;
        }
        //布控方式 人/机动车/非机动车
        int dispositionCategory = ayDispositionPlanDto.getDispositionCategory();
        switch (dispositionCategory) {
            case STRUCTURE_DISPOSITION_CATEGORY_PEOPLE:
                return controlPeopleVerify(personList, ayDispositionPlanDto);
            case STRUCTURE_DISPOSITION_CATEGORY_VEHICLE:
                return controlVehicleVerify(vehicleList, ayDispositionPlanDto);
            case STRUCTURE_DISPOSITION_CATEGORY_NON_VEHICLE:
                return controlNonVehicleVerify(nonVehicleList, ayDispositionPlanDto);
            default:
                return false;
        }
    }

    /**
     * 结构化布控行人验证
     *
     * @param personList
     * @return
     */
    public Boolean controlPeopleVerify(List<AYPerson> personList, AyDispositionPlanDto ayDispositionPlanDto) {
        if (personList.isEmpty()) {
            return false;
        }
        String dispositionText = ayDispositionPlanDto.getDispositionText();
        TextPeopleConditionDto textPeopleConditionDto = JSON.parseObject(dispositionText, TextPeopleConditionDto.class);
        //行人目前只支持文本条件布控
        if (Objects.equals(STRUCTURE_DISPOSITION_TYPE_TEST, ayDispositionPlanDto.getDispositionType())) {
            return controlTypeService.textPeopleVerify(personList, textPeopleConditionDto);
        }
        return false;
    }

    /**
     * 结构化布控车辆验证
     *
     * @param vehicleList
     * @return
     */
    public Boolean controlVehicleVerify(List<AYVehicle> vehicleList, AyDispositionPlanDto ayDispositionPlanDto) {
        if (vehicleList.isEmpty()) {
            return false;
        }
        String dispositionText = ayDispositionPlanDto.getDispositionText();
        TextVehicleConditionDto textVehicleConditionDto = JSON.parseObject(dispositionText, TextVehicleConditionDto.class);
        Integer dispositionType = ayDispositionPlanDto.getDispositionType();
        switch (dispositionType) {
            case STRUCTURE_DISPOSITION_TYPE_TEST:
                return controlTypeService.textVehicleVerify(vehicleList, textVehicleConditionDto);
            case STRUCTURE_DISPOSITION_TYPE_IMAGE:
                return false;
            case STRUCTURE_DISPOSITION_VEHICLE_TYPE_GROUP:
                return vehicleGroupVerify(vehicleList, ayDispositionPlanDto);
            default:
                return false;
        }
    }

    /**
     * 结构化布控非机动车验证
     *
     * @param nonVehicleList
     * @return
     */
    public Boolean controlNonVehicleVerify(List<AYNonVehicle> nonVehicleList, AyDispositionPlanDto ayDispositionPlanDto) {
        if (nonVehicleList.isEmpty()) {
            return false;
        }
        String dispositionText = ayDispositionPlanDto.getDispositionText();
        TextNonVehicleConditionDto textNonVehicleConditionDto = JSON.parseObject(dispositionText, TextNonVehicleConditionDto.class);
        //非机动车目前只支持文本条件布控
        if (Objects.equals(STRUCTURE_DISPOSITION_TYPE_TEST, ayDispositionPlanDto.getDispositionType())) {
            return controlTypeService.textNonVehicleVerify(nonVehicleList, textNonVehicleConditionDto);
        }
        return false;
    }

    /**
     * 结构化遮挡车牌验证
     *
     * @param vehicles
     */
    public Boolean coverVehicleVerify(List<AYVehicle> vehicles) {
        if (vehicles.isEmpty()) {
            return false;
        }
        Iterator<AYVehicle> vehicleIterator = vehicles.iterator();
        while (vehicleIterator.hasNext()) {
            AYVehicle vehicle = vehicleIterator.next();
            String hasPlate = vehicle.getHasPlate();
            String isCovered = vehicle.getIsCovered();
            String trueStr = String.valueOf(BooleanUtil.toInt(true));
            if (Objects.equals(trueStr, hasPlate) || Objects.equals(trueStr, isCovered)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 结构化车辆库验证
     *
     * @param vehicles
     */
    public Boolean vehicleGroupVerify(List<AYVehicle> vehicles, AyDispositionPlanDto ayDispositionPlanDto) {
        //识别车辆对象为空
        if (vehicles.isEmpty()) {
            return false;
        }
        String dtoVehicleGroupIds = ayDispositionPlanDto.getVehicleGroup();
        //无车辆组集合id
        if (StrUtil.isBlank(dtoVehicleGroupIds)) {
            return false;
        }
        List<String> vehicleGroupIds = StrUtil.split(dtoVehicleGroupIds, SymbolConstants.COMMA);
        if (vehicleGroupIds.isEmpty()) {
            return false;
        }
        Iterator<AYVehicle> vehicleIterator = vehicles.iterator();
        while (vehicleIterator.hasNext()) {
            AYVehicle ayVehicle = vehicleIterator.next();
            String plateNo = ayVehicle.getPlateNo();
            if (StrUtil.isBlank(plateNo)) {
                return false;
            }
            //验证车辆库set集合是否有布控车牌
            for (String vehicleGroupId : vehicleGroupIds) {
                if (RedisUtil.sHasKey(VEHICLE_GROUP + vehicleGroupId, plateNo)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 布控前置验证
     *
     * @param ayDispositionPlanDto
     * @return
     */
    public Boolean controlFrontVerify(AyDispositionPlanDto ayDispositionPlanDto, Long markTime) {
        //验证时间段
//        long beginTime = ayDispositionPlanDto.getBeginTime().atZone(ZoneId.systemDefault()).toEpochSecond();
//        long endTime = ayDispositionPlanDto.getEndTime().atZone(ZoneId.systemDefault()).toEpochSecond();
//        if (markTime < beginTime || endTime > markTime) {
//            return false;
//        }
        //验证布防撤防状态
        Integer status = ayDispositionPlanDto.getStatus();
        Integer defenseStatus = ayDispositionPlanDto.getDefenseStatus();
        int trueInt = BooleanUtil.toInt(true);
        if (!Objects.equals(status, trueInt) || !Objects.equals(defenseStatus, trueInt)) {
            return false;
        }
        return true;
    }

    /**
     * 布控模板验证
     *
     * @param ayDispositionPlanDto
     * @return
     */
    public Boolean controlPlanVerify(AyDispositionPlanDto ayDispositionPlanDto) {
        int planType = ayDispositionPlanDto.getPlanType();
        PlanTypeEnum planTypeEnum = PlanTypeEnum.getByValue(planType);
        //判断计划类型是否合法
        if (Objects.isNull(planTypeEnum)) {
            return false;
        }


        String planInfoList = ayDispositionPlanDto.getPlanInfoList();
        List<List<TimeSpanDto>> planInfoDtoS;
        try {
            planInfoDtoS = JSON.parseObject(planInfoList, new TypeReference<List<List<TimeSpanDto>>>() {
            });
        } catch (Exception e) {
            log.error("{}--", JSON_PARSE_ERROR, e);
            return false;
        }

        switch (planTypeEnum) {
            case ALL_DAY_PLAN:
                return true;
            case WEEK_PLAN:
            case DAY_PLAN:
                return weekPlanVerify(planInfoDtoS);
            default:
                return false;
        }
    }

    /**
     * 周计划验证
     *
     * @param planInfoDtoS
     * @return
     */
    public Boolean weekPlanVerify(List<List<TimeSpanDto>> planInfoDtoS) {
        int thisDayOfWeek = com.relytosoft.mizar.analyze.common.utils.DateUtil.thisDayOfWeek();
        //星期一取get(0)
        List<TimeSpanDto> timeSpanDtos = planInfoDtoS.get(thisDayOfWeek - 1);
        //当前计划模板的当前天计划
        if (timeSpanDtos.isEmpty()) {
            return false;
        }
        return dayPlanVerify(timeSpanDtos);
    }

    /**
     * 天计划验证
     *
     * @param timeSpanDtos
     * @return
     */
    public Boolean dayPlanVerify(List<TimeSpanDto> timeSpanDtos) {
        if (timeSpanDtos.isEmpty()) {
            return false;
        }
        Iterator<TimeSpanDto> dtosIterator = timeSpanDtos.iterator();
        while (dtosIterator.hasNext()) {
            TimeSpanDto timeSpanDto = dtosIterator.next();
            if (timeSpanVerify(timeSpanDto)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 时间段验证
     *
     * @param timeSpanDto
     * @return
     */
    public Boolean timeSpanVerify(TimeSpanDto timeSpanDto) {
        if (Objects.isNull(timeSpanDto)) {
            return false;
        }
        if (Objects.isNull(timeSpanDto.getEndTime()) || Objects.isNull(timeSpanDto.getStartTime())) {
            return false;
        }
        Long startTime = Long.valueOf(timeSpanDto.getStartTime());
        Long endTime = Long.valueOf(timeSpanDto.getEndTime());
        Long nowTime = DateUtil.current();
        if (startTime > nowTime || endTime < nowTime) {
            return false;
        }
        return true;
    }

}
